package com.flyco.modules.stm.service.impl;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.flyco.common.api.vo.Result;
import com.flyco.modules.pms.entity.PmsSkuStock;
import com.flyco.modules.pms.service.IPmsSkuStockService;
import com.flyco.modules.stm.entity.StmChannelPrice;
import com.flyco.modules.stm.entity.StmChannelStoreRelation;
import com.flyco.modules.stm.entity.StmJdChannelPrice;
import com.flyco.modules.stm.entity.StmStoreInfo;
import com.flyco.modules.stm.mapper.StmChannelPriceMapper;
import com.flyco.modules.stm.service.*;
import com.flyco.poi.excel.ExcelImportUtil;
import com.flyco.poi.excel.entity.ImportParams;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;



/**
 * @Description: 渠道产品表
 * @Author: flyco
 * @Date: 2023-06-21
 * @Version: V1.0
 */
@Slf4j
@Service
public class StmChannelPriceServiceImpl extends ServiceImpl<StmChannelPriceMapper, StmChannelPrice> implements IStmChannelPriceService {
    @Autowired
    private IStmJdChannelPriceService stmJdChannelProductService;
    @Autowired
    private IPmsSkuStockService skuStockService;
    @Autowired
    private IStmStoreInfoService stmStoreInfoService;
    @Autowired
    private IStmChannelStoreRelationService stmChannelStoreRelationService;
    @Autowired
    private StmChannelPriceServiceImpl stmChannelPriceService;
    private StmChannelPriceMapper  stmChannelPriceMapper;


    /**
     * 定时任务，每天夜里1点执行一次，
     * 查询stm_jd_channel_product视图，把商品，价格信息，提取出有效的，新增或者更新到stm_channel_product_jd表
     */
    @Override
    public String setChannelPrice() {
        //查询允许同步的经销商，只同步这些经销商的价格信息
        /*List<StmStoreInfo> storeInfoList = stmStoreInfoService.list(Wrappers.lambdaQuery(StmStoreInfo.class).eq(StmStoreInfo::getDpFlag,1));
        if(storeInfoList.isEmpty()){
            return "没有要同步的经销商";
        }*/

        //查询同步的金蝶价格信息
        List<StmJdChannelPrice> jdList = getJdPrices();
        if (jdList.isEmpty()) {
            return "没有查到价格信息";
        }

        Map<String, String> result = new HashMap<>();
        //result.put("要同步的经销商id",storeInfoList.stream().map(StmStoreInfo::getId).collect(Collectors.joining(",")));
        result.put("查询到的价格数据", jdList.size() + "条");

        //查询小程序系统现在的价格
        List<StmChannelPrice> prices = this.list();

        Date date = new Date();

        //刷新价格表
        flushPrice(date, prices, jdList, result);

        //刷新经销商商品表
//        flushProduct(date,jdList, storeInfoList, result);

        String msg = JSONUtil.toJsonStr(result);
        log.info("setChannelPrice执行结果：{}", msg);
        return msg;
    }

    /**
     * 刷新价格
     * 存在3种可能性：新增，删除，修改
     */
    private void flushPrice(Date date, List<StmChannelPrice> prices, List<StmJdChannelPrice> jdPrices, Map<String, String> result) {
        //新增
        addPrice(date, prices, jdPrices, result);

        //删除
        deletePrice(date, prices, jdPrices, result);

        //修改
        updatePrice(date, prices, jdPrices, result);
    }

    /**
     * 刷新经销商的商品
     * 存在3种可能性：新增，删除，修改
     * 根据金蝶的经销商和商品的关系，更新PmsSkuStock表
     */
    private void flushProduct(Date date, List<StmJdChannelPrice> jdProduct, List<StmStoreInfo> storeInfoList, Map<String, String> result) {
        //查询经销商的现有商品信息
        List<PmsSkuStock> products = skuStockService.list(Wrappers.lambdaQuery(PmsSkuStock.class)
                .in(PmsSkuStock::getStoreIdStr, storeInfoList.stream().map(StmStoreInfo::getId).collect(Collectors.toList()))
                .eq(PmsSkuStock::getCancelFlag, 0));
        Map<String, List<PmsSkuStock>> storeProductsMap = products.stream().collect(Collectors.groupingBy(PmsSkuStock::getStoreIdStr));

        //根据经销商分组，分别做处理
        Map<String, List<StmJdChannelPrice>> jdProducts = jdProduct.stream().filter(q -> StrUtil.isNotBlank(q.getStoreId())).collect(Collectors.groupingBy(StmJdChannelPrice::getStoreId));
        if (!jdProducts.isEmpty()) {
            process(date, storeProductsMap, jdProducts);
        }

        //根据渠道分组
        Map<String, List<StmJdChannelPrice>> jdProducts2 = channelToJdProducts(jdProduct);
        if (!jdProducts2.isEmpty()) {
            process(date, storeProductsMap, jdProducts2);
        }
    }

    /**
     * 把渠道格式转换为经销商格式
     *
     * @param jdProduct
     * @return
     */
    private Map<String, List<StmJdChannelPrice>> channelToJdProducts(List<StmJdChannelPrice> jdProduct) {
        Map<String, List<StmJdChannelPrice>> channelCollect = jdProduct.stream().filter(q -> StrUtil.isNotBlank(q.getChannelId())).collect(Collectors.groupingBy(StmJdChannelPrice::getStoreId));
        if (channelCollect.isEmpty()) {
            return new HashMap<>();
        }
        //查询这些渠道对应的供应商
        Map<String, List<StmChannelStoreRelation>> collect = stmChannelStoreRelationService.list(Wrappers.lambdaQuery(StmChannelStoreRelation.class).eq(StmChannelStoreRelation::getStatus, 9)
                .in(StmChannelStoreRelation::getChannelId, channelCollect.keySet())).stream().collect(Collectors.groupingBy(StmChannelStoreRelation::getChannelIdStr));
        if (collect.isEmpty()) {
            return new HashMap<>();
        }

        //把渠道替换为经销商
        Map<String, List<StmJdChannelPrice>> map = new HashMap<>();
        channelCollect.forEach((channelId, list) -> {
            //获取该渠道下面的经销商
            List<StmChannelStoreRelation> relations = collect.get(channelId);
            if (relations != null) {
                relations.forEach(one -> {
                    map.put(one.getStoreIdStr(), list);
                });
            }
        });

        return map;
    }

    /**
     * 每个经销商分别处理
     *
     * @param date
     * @param storeProductsMap
     * @param jdStoreProductsMap
     */
    private void process(Date date, Map<String, List<PmsSkuStock>> storeProductsMap, Map<String, List<StmJdChannelPrice>> jdStoreProductsMap) {
        jdStoreProductsMap.forEach((storeId, jdStoreProducts) -> {
            List<PmsSkuStock> storeProducts = storeProductsMap.get(storeId);
            if (storeProducts != null) {
                addStoreProducts(date, storeProducts, jdStoreProducts);
                deleteStoreProducts(date, storeProducts, jdStoreProducts);
            } else {
                //为空的，新增这个新的经销商
                List<PmsSkuStock> collect = jdStoreProducts.stream().map(one -> {
                    PmsSkuStock pmsSkuStock = new PmsSkuStock();
                    pmsSkuStock.setStoreIdStr(one.getStoreId());
                    pmsSkuStock.setSkuCode(one.getSkuCode());
                    pmsSkuStock.setCreateTime(date);
                    pmsSkuStock.setStoreIdStr(one.getStoreId());
                    //查询stm_store_info表
                    StmStoreInfo stmStoreInfo = stmStoreInfoService.getById(one.getStoreId());
                    if (stmStoreInfo != null) {
                        pmsSkuStock.setStoreId(stmStoreInfo.getStoreId());
                        pmsSkuStock.setChannelId(Integer.parseInt(stmStoreInfo.getChannelId()));
                        pmsSkuStock.setChannelIdStr(stmStoreInfo.getChannelId());
                    }
                    return pmsSkuStock;
                }).collect(Collectors.toList());
                if (!collect.isEmpty()) {
                    skuStockService.saveBatch(collect);
                }
            }
        });
    }

    /**
     * 找出list中没有的，做新增
     */
    private void addStoreProducts(Date date, List<PmsSkuStock> storeProducts, List<StmJdChannelPrice> jdStoreProducts) {
        Map<String, PmsSkuStock> map = storeProducts.stream().collect(Collectors.toMap(PmsSkuStock::getSkuCode, a -> a));
        List<PmsSkuStock> collect = jdStoreProducts.stream().filter(q -> map.get(q.getSkuCode()) == null).map(one -> {
            PmsSkuStock pmsSkuStock = new PmsSkuStock();
            pmsSkuStock.setStoreIdStr(one.getStoreId());
            pmsSkuStock.setSkuCode(one.getSkuCode());
            pmsSkuStock.setCreateTime(date);
            PmsSkuStock template = storeProducts.get(0);
            pmsSkuStock.setStoreId(template.getStoreId());
            pmsSkuStock.setChannelId(template.getChannelId());
            pmsSkuStock.setChannelIdStr(template.getChannelIdStr());
            return pmsSkuStock;
        }).collect(Collectors.toList());
        if (!collect.isEmpty()) {
            skuStockService.saveBatch(collect);
        }
    }

    /**
     * 找出jdList中没有的，做删除
     */
    private void deleteStoreProducts(Date date, List<PmsSkuStock> storeProducts, List<StmJdChannelPrice> jdStoreProducts) {
        Map<String, StmJdChannelPrice> map = jdStoreProducts.stream().collect(Collectors.toMap(StmJdChannelPrice::getSkuCode, a -> a));
        List<PmsSkuStock> collect = storeProducts.stream().filter(q -> map.get(q.getSkuCode()) == null).collect(Collectors.toList());
        if (!collect.isEmpty()) {
            collect.forEach(one -> {
                one.setCancelFlag(1);
                one.setUpdateTime(date);
            });
            skuStockService.updateBatchById(collect);
        }
    }

    /**
     * 找出list中没有的，做新增
     */
    private void addPrice(Date date, List<StmChannelPrice> prices, List<StmJdChannelPrice> jdPrices, Map<String, String> result) {
        Map<String, StmChannelPrice> map = prices.stream().filter(q -> q.getUniCode() != null).collect(Collectors.toMap(StmChannelPrice::getUniCode, a -> a));
        List<StmChannelPrice> collect = jdPrices.stream().filter(q -> map.get(q.getUniCode()) == null).map(one -> {
            StmChannelPrice stmChannelPrice = new StmChannelPrice();
            stmChannelPrice.setChannelId(one.getChannelId());
            stmChannelPrice.setStoreId(one.getStoreId());
            stmChannelPrice.setSkuCode(one.getSkuCode());
            stmChannelPrice.setPrice(one.getPrice());
            stmChannelPrice.setUniCode(one.getUniCode());
            stmChannelPrice.setCreateTime(date);
            return stmChannelPrice;
        }).collect(Collectors.toList());

        if (!collect.isEmpty()) {
            this.saveBatch(collect);
        }
        result.put("新增价格数据", collect.size() + "条");
    }

    /**
     * 同步的数据中不存在的，删除
     */
    private void deletePrice(Date date, List<StmChannelPrice> prices, List<StmJdChannelPrice> jdPrices, Map<String, String> result) {
        Map<String, List<StmJdChannelPrice>> map = jdPrices.stream().collect(Collectors.groupingBy(StmJdChannelPrice::getUniCode));
        List<StmChannelPrice> list = prices.stream().filter(q -> map.get(q.getUniCode()) == null).collect(Collectors.toList());
        //过滤出有效的
        List<StmChannelPrice> collect = list.stream().filter(q -> q.getStatus() == 1).collect(Collectors.toList());
        //设置为无效
        if (!collect.isEmpty()) {
            collect.forEach(one -> {
                one.setStatus(0);
                one.setUpdateTime(date);
            });
            this.updateBatchById(collect);
        }
        result.put("删除价格数据", collect.size() + "条");
    }

    /**
     * 存在的数据，如果价格有变化，要更新
     */
    private void updatePrice(Date date, List<StmChannelPrice> prices, List<StmJdChannelPrice> jdPrices, Map<String, String> result) {
        Map<String, StmChannelPrice> map = prices.stream().filter(q -> q.getUniCode() != null).collect(Collectors.toMap(StmChannelPrice::getUniCode, a -> a));
        int count = 0;
        for (StmJdChannelPrice one : jdPrices) {
            StmChannelPrice stmChannelPrice = map.get(one.getUniCode());
            if (stmChannelPrice != null) {
                //价格不相等的，或者状态是删除的，做更新
                if (stmChannelPrice.getPrice().compareTo(one.getPrice()) != 0 || stmChannelPrice.getStatus() == 0) {
                    stmChannelPrice.setPrice(one.getPrice());
                    //设置为有效
                    stmChannelPrice.setStatus(1);
                    stmChannelPrice.setUpdateTime(date);
                    this.updateById(stmChannelPrice);
                    count++;
                }
            }
        }
        result.put("更新价格数据", count + "条");
    }

    /**
     * 查询从金蝶同步数据的价格
     *
     * @return
     */
    private List<StmJdChannelPrice> getJdPrices() {
        LocalDate now = LocalDate.now();
        List<StmJdChannelPrice> jdPriceList = stmJdChannelProductService.jdPriceList();
        /*List<StmJdChannelPrice> jdPriceList = stmJdChannelProductService.list(Wrappers.lambdaQuery(StmJdChannelPrice.class)
                .and(a->a.in(StmJdChannelPrice::getStoreId,storeInfoList.stream().map(StmStoreInfo::getId).collect(Collectors.toList()))
                        .or()
                        .in(StmJdChannelPrice::getChannelId,storeInfoList.stream().map(StmStoreInfo::getChannelId).distinct().collect(Collectors.toList())))
                .orderByDesc(StmJdChannelPrice::getEffectiveDate));*/
        //根据uniCode分组（同一个商家同一个商品多个价格段时，uniCode值一样）,取出当前时间适用的价格
        List<StmJdChannelPrice> jdPrices = new ArrayList<>();
        jdPriceList.stream().collect(Collectors.groupingBy(StmJdChannelPrice::getUniCode)).forEach((storeId, list) -> {
            list.stream().filter(q -> now.compareTo(q.getEffectiveDate()) >= 0).findFirst().ifPresent(jdPrices::add);
        });
        return jdPrices;
    }


    @Override
    public List<StmChannelPrice> getByChannelId(String channelId) {
        LambdaQueryWrapper<StmChannelPrice> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StmChannelPrice::getChannelId, channelId)
                .eq(StmChannelPrice::getStatus, 1);
        return list(wrapper);
    }

    @Override
    public List<StmChannelPrice> getByStoreId(String storeId) {
        LambdaQueryWrapper<StmChannelPrice> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StmChannelPrice::getStoreId, storeId)
                .eq(StmChannelPrice::getStatus, 1);
        return list(wrapper);
    }

    @Override
    public List<String> getSkuCodeListByPartnerId(Long partnerId) {
        LambdaQueryWrapper<StmChannelPrice> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StmChannelPrice::getPartnerId, partnerId)
                .eq(StmChannelPrice::getStatus, 1);
        return list(wrapper).stream().map(StmChannelPrice::getSkuCode).distinct().collect(Collectors.toList());
    }

    @Override
    public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response, Class<StmChannelPrice> clazz) {

        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
        for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) {
            MultipartFile file = entity.getValue();// 获取上传文件对象
            ImportParams params = new ImportParams();
            params.setTitleRows(2);
            params.setHeadRows(1);
            params.setNeedSave(true);
            try {
                List<StmChannelPrice> list = ExcelImportUtil.importExcel(file.getInputStream(), clazz, params);
                list.forEach(item -> {
                    item.setPartnerId(4100L);
                    item.setUniCode(item.getSkuCode() + item.getChannelId() + item.getStoreId());
                });
                //update-begin-author:taoyan date:20190528 for:批量插入数据
                long start = System.currentTimeMillis();
                stmChannelPriceService.saveOrUpdateBatch(list);
                //400条 saveBatch消耗时间1592毫秒  循环插入消耗时间1947毫秒
                //1200条  saveBatch消耗时间3687毫秒 循环插入消耗时间5212毫秒
                log.info("消耗时间" + (System.currentTimeMillis() - start) + "毫秒");
                //update-end-author:taoyan date:20190528 for:批量插入数据
                return Result.ok("文件导入成功！数据行数：" + list.size());
            } catch (Exception e) {
                log.error(e.getMessage(), e);
                return Result.error("文件导入失败:" + e.getMessage());
            } finally {
                try {
                    file.getInputStream().close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return Result.error("文件导入失败！");
    }

    @Override
    public void deleteId(String id) {
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("id", id);
        stmChannelPriceMapper.delete(queryWrapper);

    }
}
